package com.gitee.luosl.cola.match.pattern;

import com.gitee.luosl.cola.lang.Tuple2;

import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * Created by luosl on 2021/03/30/9:46
 */
abstract public class Pattern2<T, T1, T2> implements Pattern<T, Tuple2<T1, T2>> {

    public static <T, T1, T2, R1, R2> Pattern2<T, R1, R2> of(
            Class<? super T> clazz,
            Predicate<T> predicate,
            Pattern<T1, R1> pattern1, Pattern<T2, R2> pattern2,
            Function<T, Tuple2<T1, T2>> unapply) {

        return new Pattern2<T, R1, R2>() {

            @Override
            public boolean isDefinedAt(T value) {
                Tuple2<T1, T2> unapplyValue = unapply.apply(value);
                return clazz.isInstance(value)
                        && predicate.test(value)
                        && pattern1.isDefinedAt(unapplyValue._1)
                        && pattern2.isDefinedAt(unapplyValue._2);
            }

            @Override
            public Tuple2<R1, R2> apply(T value) {
                return unapply.apply(value).map(pattern1::apply, pattern2::apply);
            }
        };
    }

    public static <T, T1, T2> Pattern2<T, T1, T2> of(Pattern<T, Tuple2<T1, T2>> pattern){
        return new Pattern2<T, T1, T2>() {
            @Override
            public boolean isDefinedAt(T value) {
                return pattern.isDefinedAt(value);
            }

            @Override
            public Tuple2<T1, T2> apply(T value) {
                return pattern.apply(value);
            }
        };
    }

}
